package trackingAlgorithms;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.media.Buffer;
import javax.media.format.VideoFormat;
import javax.media.util.ImageToBuffer;
import javax.swing.JSlider;

import trackingAlgorithms.blob.Blob;
import trackingAlgorithms.videoprocessing.RgbVideoEffect;
import algos.Isovist;
import camera.AbstractCamera;
import com.jme3.math.Vector3f;
import environment.AbstractEnvironment;

public class FrameProcessor {

    private final int FRAMES_TO_CREATE_BACKGROUND = 20;
    private int num;
    public Tracker tracker;
    public ArrayList<Blob> blobs;
    private boolean created = false;
    private ArrayList<AbstractCamera> cameras;
    private Isovist[] iso; // implementation of visibility polygon
    public boolean canSee[];
    public int fromTo[];
    AbstractEnvironment env;
    private boolean createHistory = false;

    public FrameProcessor(AbstractEnvironment env, ArrayList<AbstractCamera> cameras, JSlider minBlobSizeSlider, JSlider thresholdSlider) {
        this.cameras = cameras;
        tracker = new Tracker(FRAMES_TO_CREATE_BACKGROUND, cameras, minBlobSizeSlider, thresholdSlider);
        blobs = new ArrayList<Blob>();
        canSee = new boolean[cameras.size()];
        this.env = env; // environment of Experiment scene
        Area area = env.getArea();
        iso = new Isovist[cameras.size()];
        for (int i = 0; i < cameras.size(); i++) {  //create visibility polygon for each camera
            iso[i] = new Isovist(area);
        }
        tracker.setIsovist(iso);
    }

    /**
     * This function takes a captured frame and processes the frame
     * @param frame
     * 				The captured frame to be processed.
     */
    public void processFrame(BufferedImage frame, BufferedImage coloredImage) {

        Buffer buf = ImageToBuffer.createBuffer(frame, FRAMES_TO_CREATE_BACKGROUND);
        
        VideoFormat vf = (VideoFormat) buf.getFormat();
        if (num < FRAMES_TO_CREATE_BACKGROUND) {
            tracker.addImage(frame, coloredImage, num);//save this frames to create the background from them
        } else {
            if (!created) {
                System.out.println("create!");
                tracker.createBackGround(); // create the background
                created = true;
                return;
            }
            // process frame and extract blobs
            tracker.processFrame(frame, coloredImage, vf);
            blobs = tracker.blobs;


            Graphics2D g2 = coloredImage.createGraphics();
            //draw the blobs
            for (Blob blob : blobs) {
                g2.setColor(Color.red);
                int x = blob.bounds.x;
                int y = (vf.getSize().height - blob.bounds.y) - blob.bounds.height;
                int width = blob.bounds.width;
                int height = blob.bounds.height;
                g2.drawRect(x, y, width, height);
                g2.drawString(blob.frameLabel + "", x + blob.bounds.width / 2, y + blob.bounds.height / 2);
            }

            // Calculate visibility Polygon for each camera.
            for (int i = 0; i < iso.length; i++) {
                Point cam = new Point((int) cameras.get(i).getLocation().x, (int) cameras.get(i).getLocation().z);
                iso[i].doIso(cam);
            }

            // draw white polygons around obstacles
//            g2.setColor(Color.GREEN);
//            g2.draw(env.getArea());
//            for (Area wall : env.getObstacles()) {
//                g2.draw(wall);
//            }
            // draw yellow line shows camera direction.
            // draw blue line between the camera and the object assigned to it.
            canSee = new boolean[cameras.size()];
            try{
	            if (tracker.tUpdator.to.size() > 0) {
	                for (int i = 0; i < tracker.tUpdator.from.size(); i++) { 
	                    Point from = new Point((int) tracker.tUpdator.from.get(i).x, (int) tracker.tUpdator.from.get(i).z);
	                    Point to = new Point((int) tracker.tUpdator.to.get(i).x, (int) tracker.tUpdator.to.get(i).z);
	                    int index = getIndexOf(from);
	                    boolean cS = tracker.tUpdator.isInsideVisibilityPolygon(null, new Vector3f(to.x, 0, to.y), index);
	                    g2.setColor(cS ? Color.RED : Color.blue);
	                    canSee[index] = cS;
	                    g2.drawLine((int) cameras.get(index).getLocation().x, (int) cameras.get(index).getLocation().z, to.x, to.y);  // draw blue line from camera to the object tracked by it
	                    g2.setColor(Color.YELLOW);
	                    for (AbstractCamera camera : cameras) // draw yellow line representing direction of the camera.
	                    {
	                        g2.drawLine((int) camera.getLocation().x, (int) camera.getLocation().z, (int) camera.getDirection().x, (int) camera.getDirection().z);
	                    }
	                }
	            }
            }catch(Exception e){
//            	System.out.println("NULL");
            }
        }
        num++;
//        try {
//            ImageIO.write(coloredImage, "png", new File("img_"+num+".png"));
//        } catch (IOException ex) {
////            Logger.getLogger(FrameProcessor.class.getName()).log(Level.SEVERE, null, ex);
//        }

    }

    public int getIndexOf(Point from) {
        int i = 0;
        for (AbstractCamera cam : cameras) {
            if ((int) cam.getLocation().x == from.x && (int) cam.getLocation().z == from.y) {
                return i;
            }
            i++;
        }
        return -1;
    }
}
